#
#2008 Julka Lipkova
#

import pygtk
pygtk.require('2.0')
import gtk
import copy

from glyphdb import glyphDB
import config
import math

class Checker ():
    def __init__(self, id):
        self.model_ = glyphDB.getGlyphByID( id )
        self.model = copy.deepcopy(self.model_)
        self.model.lines  = [ x[0:len(x):10] for x in self.model_.lines ]
        self.resStr = []

    def fitX(self, lineList):
        shiftx = self.model.lines[0][0][0] - lineList[0][0][0]
        for line in lineList:
            for i in range(len(line)):
                x,y = line[i]
                x = x + shiftx
                line[i] = x,y
        print 'shiftx = %d' % ( shiftx, )
    
    def fitXY(self, lineList):
        for line1, line2, l in zip( lineList, self.model.lines, range( len(lineList) ) ) :
            shiftx = line2[0][0] - line1[0][0]
            shifty = line2[0][1] - line1[0][1]
            if ( config.SHIFTMODE == 1 ):
                sminxp, sminyp, smaxxp, smaxyp, mminxp, mminyp, mmaxxp, mmaxyp = (0,)*8
                for i, point in zip( range(len(line1)), line1 ) :
                    if ( point[0] > line1[smaxxp][0] ):
                        smaxxp = i
                    if ( point[0] < line1[sminxp][0] ):
                        sminxp = i
                    if ( point[1] > line1[smaxyp][1] ):
                        smaxyp = i
                    if ( point[1] < line1[sminyp][1] ):
                        sminyp = i
                for i, point in zip( range(len(line2)), line2 ) :
                    if ( point[0] > line2[mmaxxp][0] ):
                        mmaxxp = i
                    if ( point[0] < line2[mminxp][0] ):
                        mminxp = i
                    if ( point[1] > line2[mmaxyp][1] ):
                        mmaxyp = i
                    if ( point[1] < line2[mminyp][1] ):
                        mminyp = i
                shiftx = line2[mminxp][0] - line1[sminxp][0];
                shifty = line2[mminyp][1] - line1[sminyp][1];

            for i in range(len(line1)):
                x,y = line1[i]
                x = x + shiftx
                x = x + shifty
                line1[i] = x,y

    def fitWidthHeight(self, lineList):
#       TODO: use reduce( min, ... )
        for line1, line2, l in zip( lineList, self.model.lines, range( len(lineList) ) ) :
            sminxp, sminyp, smaxxp, smaxyp, mminxp, mminyp, mmaxxp, mmaxyp = (0,)*8
            for i, point in zip( range(len(line1)), line1 ) :
                if ( point[0] > line1[smaxxp][0] ):
                    smaxxp = i
                if ( point[0] < line1[sminxp][0] ):
                    sminxp = i
                if ( point[1] > line1[smaxyp][1] ):
                    smaxyp = i
                if ( point[1] < line1[sminyp][1] ):
                    sminyp = i
            for i, point in zip( range(len(line2)), line2 ) :
                if ( point[0] > line2[mmaxxp][0] ):
                    mmaxxp = i
                if ( point[0] < line2[mminxp][0] ):
                    mminxp = i
                if ( point[1] > line2[mmaxyp][1] ):
                    mmaxyp = i
                if ( point[1] < line2[mminyp][1] ):
                    mminyp = i
            
            swidth = line1[smaxxp][0] - line1[sminxp][0]
            sheight = line1[smaxyp][1] - line1[sminyp][1]
            mwidth = line2[mmaxxp][0] - line2[mminxp][0]
            mheight = line2[mmaxyp][1] - line2[mminyp][1]

            if ( abs( swidth ) < config.EPS ):
                indexx = mwidth
            else:
                indexx = mwidth/swidth
            if ( abs( sheight ) < config.EPS ):
                indexy = mheight
            else:
                indexy = mheight/sheight

            beginx, beginy = line1[sminxp][0], line1[sminyp][1]
            
            if (line1[smaxyp][1]-line2[mmaxyp][1]>3.0): 
                print '%d. line -- much under the baseline' % (l+1,)
                self.resStr.append( '%d. line -- much under the baseline.' % (l+1,) )
            if (line1[smaxyp][1]-line2[mmaxyp][1]<-4.0): 
                print '%d. line -- much above the baseline' % (l+1,)
                self.resStr.append( '%d. line -- much above the baseline.' % (l+1,) )
            if (swidth-mwidth>8.0): 
                print '%d. line -- too wide' % (l+1,)
                self.resStr.append( '%d. line -- too wide.' % (l+1,) )
            if (swidth-mwidth<-2.0):
                print '%d. line -- too narrow' % (l+1,)
                self.resStr.append( '%d. line -- too narrow.' % (l+1,) )
            if (sheight-mheight>8.0): 
                print '%d. line -- too high' % (l+1,)
                self.resStr.append( '%d. line -- too high.' % (l+1,) )
            if (sheight-mheight<-3.0): 
                print '%d. line -- too small' % (l+1,)
                self.resStr.append( '%d. line -- too small.' % (l+1,) )

            for i in range(len(line1)):
                x,y = line1[i]
                x = (x - beginx)*indexx + beginx
                y = (y - beginy)*indexy + beginy
                line1[i] = x,y

    def skew(self, line, alpha):
        line = copy.deepcopy( line )
        if (abs(alpha)<0.0005):
            return line
        for i in range(len(line)):
            x,y = line[i]
            x = x + y * math.tan(alpha)
            line[i] = x,y
        return line

    def dist(self, a, b):
        return ( (a[0]-b[0])**2 + (a[1]-b[1])**2 )

    def dtw(self, mod, scr):
        tmp = []
        d = [ tmp ]
        tmp.append( self.dist( mod[0], scr[0] ) )
        for i in range(1, len(scr)):
            tmp.append( self.dist( mod[0], scr[i] ) + tmp[i-1] )
        for t in range(1, len(mod)):
            tmp = []
            d.append( tmp )
            for i in range(len(scr)):
                if (i == 0):
                    tmp.append( self.dist( mod[t], scr[i] ) + d[t-1][i] )
                else:
                    if ( d[t-1][i-1] < d[t-1][i] and d[t-1][i-1] < tmp[i-1]):
                        tmp.append( self.dist( mod[t], scr[i] ) + d[t-1][i-1])
                    elif ( d[t-1][i] < d[t-1][i-1] and d[t-1][i] < tmp[i-1]):
                        tmp.append( self.dist( mod[t], scr[i] ) + d[t-1][i])
                    else:
                        tmp.append( self.dist( mod[t], scr[i] ) + tmp[i-1])
        return d[-1][-1]

    def fitInclination(self, lineList):
        for line, l in zip( lineList, range( len(lineList) ) ) :
            m = reduce( min, 
                    [ ( self.dtw( self.model.lines[l], self.skew(line,alpha) ), alpha)
                        for alpha in  config.rrange( -math.pi/4.0, math.pi/4.0, 0.05 )
                    ] )
            alpha = 0
            v,min_alpha = min( m, ( self.dtw( self.model.lines[l], self.skew(line,alpha) ), alpha) )
            lineList[l] = self.skew( line, min_alpha )
            if (min_alpha<-0.05):
                print '%d. line -- small inclination' % (l+1,)
                self.resStr.append( '%d. line -- small inclination.' % (l+1,) )
            if (min_alpha>0.05):
                print '%d. line -- big inclination' % (l+1,)
                self.resStr.append( '%d. line -- big inclination.' % (l+1,) )


    def check(self, scrib):
        self.resStr = []
        if ( len( scrib.lines ) != len( self.model.lines ) ):
            self.resStr.append( 'Wrong number of lines.' )
            return self.resStr

#        res = copy.deepcopy( scrib.lines )
        res = [ x[0:len(x):10] for x in scrib.lines ]
        
        # fitting scribble
        self.fitX( res )
        self.fitWidthHeight( res )
        self.fitXY( res )
        self.fitInclination( res )
        
        # checking glyph shape by dtw
        treshold = 0
        dtwsum = 0
        for l in range( len(res) ):
            treshold = treshold + max(len(res[l]),len(self.model.lines[l]))*20
            dtwsum = dtwsum + self.dtw(self.model.lines[l], res[l])
            print 'dtwsum = ' , dtwsum
            print 'treshold = ' , treshold
        if ( dtwsum > treshold ):
            self.resStr.append( ' Wrong glyph shape!' )
            print 'Wrong glyph shape'

        return self.resStr


# vim: set ts=4 sw=4 sts=4 et :
